#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "commonfun.h"

#define size_of_attribute(Struct, Attribute) sizeof(((Struct *)0)->Attribute) // 计算结构体中成员变量的大小

const uint32_t ID_SIZE = size_of_attribute(Row, id);
const uint32_t USERNAME_SIZE = size_of_attribute(Row, username);
const uint32_t EMAIL_SIZE = size_of_attribute(Row, email);
const uint32_t PAGE_SIZE = 4096;
const uint32_t ID_OFFSET = 0; // id的偏移量
const uint32_t USERNAME_OFFSET = ID_OFFSET + ID_SIZE;
const uint32_t EMAIL_OFFSET = USERNAME_OFFSET + USERNAME_SIZE;
const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;
const uint32_t ROWS_PRE_PAGE = PAGE_SIZE / ROW_SIZE;            // 计算每页中有多少行数据
const uint32_t TABLE_MAX_ROWS = ROWS_PRE_PAGE * TABLE_MAX_PAGE; // 计算一张表存放最大行

void print_row(Row *row)
{
    printf("(%d,%s)\n", row->id, row->username);
}

void *row_slot(Table *table, uint32_t row_num)
{
    uint32_t page_num = row_num / ROWS_PRE_PAGE; // 计算表存放的页数
    void *page = table->pages[page_num];
    if (page == NULL)
    {
        // 仅在尝试访问页面时分配内存
        page = table->pages[page_num] = malloc(PAGE_SIZE);
    }
    uint32_t row_offset = row_num % ROWS_PRE_PAGE;
    uint32_t byte_offset = row_offset * ROW_SIZE;
    return page + byte_offset;
}

void serialize_row(Row *source, void *destination)
{
    // memcpy函数
    memcpy(destination + ID_OFFSET, &(source->id), ID_SIZE);
    memcpy(destination + USERNAME_OFFSET, &(source->username), USERNAME_SIZE);
    memcpy(destination + EMAIL_OFFSET, &(source->email), EMAIL_SIZE);
}

void deserialize_row(void *source, Row *destination)
{
    memcpy(&(destination->id), source + ID_OFFSET, ID_SIZE);
    memcpy(&(destination->username), source + USERNAME_OFFSET, USERNAME_SIZE);
    memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);
}

Table *create_table()
{
    Table *table = malloc(sizeof(Table));
    table->num_rows = 0;
    for (uint32_t i = 0; i < TABLE_MAX_PAGE; i++)
    {
        table->pages[i] == NULL;
    }
    return table;
}

void free_table(Table *table)
{
    for (uint32_t i = 0; i < TABLE_MAX_PAGE; i++)
    {
        free(table->pages[i]);
    }
    free(table);
}

ExecuteResult execute_insert(Statement *statement, Table *table)
{
    if (table->num_rows >= TABLE_MAX_ROWS)
    {
        /* code */
        return EXECUTE_TABLE_FULL;
    }
    Row *row_to_insert = &(statement->row_to_insert);
    serialize_row(row_to_insert, row_slot(table, table->num_rows));
    table->num_rows += 1;
    return EXECUTE_SUCCESS;
}

ExecuteResult execute_select(Statement *statement, Table *table)
{
    Row row;
    for (uint32_t i = 0; i < table->num_rows; i++)
    {
        deserialize_row(row_slot(table, i), &row);
        print_row(&row);
    }
    return EXECUTE_SUCCESS;
}

ExecuteResult execute_statement(Statement *statement, Table *table)
{
    switch (statement->type)
    {
    case (STATEMENT_INSERT):
        return execute_insert(statement, table);
        break;
    case (STATEMENT_SELECT):
        return execute_select(statement, table);
        break;
    }
}

MetaCommandResult deal_meta_command(InputBuffer *inputBuffer, Table *table)
{
    if (strcmp(inputBuffer->buffer, ".exit") == 0)
    {
        close_input_buffer(inputBuffer);
        free_table(table);
        exit(EXIT_SUCCESS);
    }
    else
    {
        return META_COMMAND_UNRECOGNIZED_COMMAND;
    }
}
